﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using BaseSniffer;


namespace Sniffer
{
    public class Sniffer
    {
        [DllImport("user32.dll")]
        public static extern IntPtr SetWinEventHook(uint eventMin,
            uint eventMax,
            IntPtr hmodWinEventProc,
            WinEventDelegate lpfnWinEventProc,
            uint idProcess,
            uint idThread,
            uint dwFlags);

        [DllImport("user32.dll")]
        public static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll")]
        public static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
        [DllImport("user32.dll")]
        public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out uint ProcessId);

        public delegate void WinEventDelegate();

        public event ForegroundChangeEventHandler OnForegroundChange;
        public delegate void ForegroundChangeEventHandler(object sender, ForegroundChangeEventArgs e);

        WinEventDelegate dele;

         const uint WINEVENT_OUTOFCONTEXT = 0;
         const uint EVENT_SYSTEM_FOREGROUND = 3;


        [ImportMany(typeof(IBrowserSniffer))]
        public IEnumerable<IBrowserSniffer> sniffers;

        public event AlarmEventHandler OnTabChangedEvent;
        public string SnifferProcess;



        public Sniffer()
        {
            dele = new WinEventDelegate(WinEventProc);
            IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND,
                EVENT_SYSTEM_FOREGROUND,
                IntPtr.Zero,
                dele,
                0,
                0,
                WINEVENT_OUTOFCONTEXT);
            DoImport();
        }



        public string GetActiveWindowTitle()
        {
            const int nChars = 256;
            StringBuilder Buff = new StringBuilder(nChars);

            IntPtr handle = GetForegroundWindow();
            if (GetWindowText(handle, Buff, nChars) > 0)
            {
                return Buff.ToString();
            }
            return null;
        }

        public void WinEventProc()
        {
            DisposeBrowserSniffer(SnifferProcess);                             
            uint pid;
            GetWindowThreadProcessId(GetForegroundWindow(), out pid);
            Process p = Process.GetProcessById((int)pid);
            SnifferProcess = p.ProcessName;
            if(InitBrowserSniffer(SnifferProcess))
                return;

            if (OnForegroundChange != null)
                OnForegroundChange(this, new ForegroundChangeEventArgs(GetActiveWindowTitle()));
        }

        private void DoImport()
        {
            var catalog = new AggregateCatalog();
            catalog.Catalogs.Add(new DirectoryCatalog("SupportedBrowsers"));
            var container = new CompositionContainer(catalog);
            container.ComposeParts(this);
            foreach(var browser in sniffers)
                browser.TabChangeEvent += OnTabChanged;
        }

        private bool InitBrowserSniffer(String pName)
        {
            var browserSniffer = sniffers.FirstOrDefault(x => x.ProcessName.Equals(pName));
            if (browserSniffer != null){
                browserSniffer.StartSniff();
                return true;
            }
            return false;
            
        }

        private void OnTabChanged(object sender, TabChangeEventArgs e)
        {
            //Buble event up
            if (OnForegroundChange != null)
                OnForegroundChange(sender, new ForegroundChangeEventArgs(e.TabName));
        }

        private void DisposeBrowserSniffer(String pName)
        {

            var browserSniffer = sniffers.FirstOrDefault(x => x.ProcessName.Equals(pName));
            if (browserSniffer != null){
                browserSniffer.StopSniff();
            }
            else
            {
                //TODO: not supported browser
            }
        }
    }
}